﻿namespace TestApp.Tests
{
    using System;
    using System.Linq;
    using System.Reactive;
    using Contracts;
    using DataService;
    using Microsoft.Reactive.Testing;
    using Moq;
    using NUnit.Framework;
    using Shouldly;

    [TestFixture]
    internal class DataProviderFixture
    {
        private TestScheduler _scheduler;
        private ITestableObserver<DataEntityDto> _observer;
        private Mock<IDataRandomizer> _dataRandomizer;

        [SetUp]
        public void SetUp()
        {
            _scheduler = new TestScheduler();
            _observer = _scheduler.CreateObserver<DataEntityDto>();
            _dataRandomizer = new Mock<IDataRandomizer>();
            _dataRandomizer.Setup(i => i.GenerateIndex()).Returns(3);
            _dataRandomizer.Setup(i => i.GenerateParameterValue()).Returns(0.34d);
        }

        [Test]
        public void ShouldGenerateEntityEvery100Ms()
        {
            // Given
            var target = CreateInstance();

            // When
            using (target.CreateDataSource().Subscribe(_observer))
            {
                _scheduler.AdvanceBy(TimeSpan.FromMilliseconds(100).Ticks);
                _scheduler.AdvanceBy(TimeSpan.FromMilliseconds(100).Ticks);
                _scheduler.AdvanceBy(TimeSpan.FromMilliseconds(100).Ticks);

                // Then
                _observer.Messages.Count(i => i.Value.Kind == NotificationKind.OnNext).ShouldBe(3);
            }
        }

        [Test]
        public void ShouldCreateValidDataEntityWhenGenerate()
        {
            // Given
            var target = CreateInstance();
            using (target.CreateDataSource().Subscribe(_observer))
            {
                _scheduler.AdvanceBy(TimeSpan.FromMilliseconds(100).Ticks);

                // When
                var entity = _observer.Messages[0].Value.Value;

                // Then
                entity.Index.ShouldBe(3);
                foreach (var parameter in entity.Parameters)
                {
                    parameter.ShouldBe(0.34d);
                }
            }
        }

        [Test]
        public void ShouldGenerateEntityTheSameEveryForEachSubscriber()
        {
            // Given
            var target = CreateInstance();
            var observer2 = _scheduler.CreateObserver<DataEntityDto>();

            // When
            using (target.CreateDataSource().Subscribe(_observer))
            {
                using (target.CreateDataSource().Subscribe(observer2))
                {
                    _scheduler.AdvanceBy(TimeSpan.FromMilliseconds(100).Ticks);

                    // Then
                    _observer.Messages.Count(i => i.Value.Kind == NotificationKind.OnNext).ShouldBe(1);
                    observer2.Messages.Count(i => i.Value.Kind == NotificationKind.OnNext).ShouldBe(1);
                    _observer.Messages[0].Value.Value.ShouldBe(observer2.Messages[0].Value.Value);
                }
            }
        }

        private IDataProvider CreateInstance()
        {
            return new DataProvider(_scheduler, _dataRandomizer.Object);
        }
    }
}
